﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Web.Security;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using PS.Practices.SiteBuilder.Features.Schema;
using PS.Practices.SiteBuilder.Features.Schema.DOM;
using PS.Practices.Provisioner.Util;

namespace PS.Practices.Provisioner.Provisioner.Schema.Logic
{
    public class OmListOperationVisitor : IListOperationVisitor
    {
        //private SPWeb web;
        private SPList list;
        private SPWeb web;
        private Dictionary<string, object> properties; 

        public OmListOperationVisitor(SPList list, SPWeb web, Dictionary<string, object> properties )
        {
            this.list = list;
            this.web = web;
            this.properties = properties;
        }

        public void Visit(SetSendToLocation setSendToLocation)
        {
            string Url = setSendToLocation.Url;

            if (string.IsNullOrEmpty(setSendToLocation.Name))
            {
                Logger.Info("Required attribute Name is missing");
                return;
            }

            if (string.IsNullOrEmpty(Url))
            {
                Logger.Info("Required attribute Url is missing");
                return;
            }

            Url = ParserUtil.ReplaceLiveFields(Url, web);
            if (Url.StartsWith("./"))
            {
                Url = web.Url + Url.Substring(2);
            }
            else
            {
                if (Url.StartsWith("~/"))
                {
                    SPWeb rootWeb = web.Site.RootWeb;
                    Url = rootWeb.Url.TrimEnd('/') + Url.Substring(1);
                }
            }

            list.SendToLocationName = setSendToLocation.Name;
            list.SendToLocationUrl = Url;

            list.Update();
        }

        public void Visit(List l)
        {
            OmWebOperationVisitorHelpers.ProcessList(this, l, list);
        }

        public void Visit(UpdateTitle updateTitle)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();

            if (!string.IsNullOrEmpty(updateTitle.Set))
            {
                list.Title = ParserUtil.ReplaceLiveFields(updateTitle.Set, list, web);
            }
            else
            {
                foreach (Replace replace in updateTitle.ReplaceInfo)
                {
                    dic.Add(replace.Match, replace.Value);
                }

                ParserUtil.UpdateListTitle(list, null, dic);
            }
            list.Update();
        }

        public void Visit(UpdateFields updateFields)
        {
            try
            {
                foreach (UpdateField field in updateFields.Fields)
                {
                    field.Process(web, list);
                }
            }
            catch (Exception e)
            {
                Logger.Info("Exception occured while updating fields");
                Logger.Error(e);
            }

            list.Update();
        }

        public void Visit(ReorderCTypes reorderCTypes)
        {
            ListUtil.ReorderCTypes(list);
        }

        public void Visit(RemoveCTypes removeCTypes)
        {
            foreach (ContentTypeRef contentType in removeCTypes.ContentTypes)
            {
                ListUtil.RemoveCType(list, contentType.ID);
            }

            list.Update();
        }

        public void Visit(ListItem listItem)
        {
            if ((listItem.SyncWithPropertyBag) || listItem.Columns.Count > 0)
            {
                Guid itemGuid = new Guid();

                // Add text columns based on property bag key/value pairs
                if (listItem.SyncWithPropertyBag)
                {
                    // Add the columns to the new list if they haven't been added already
                    foreach (var prop in properties)
                    {
                        ListUtil.EnsureListField(list, prop.Key);
                    }

                    SPListItem item2 = list.Items.Add();
                    // Add item to list
                    foreach (var prop in properties)
                    {
                        item2[prop.Key] = prop.Value;
                    }
                    item2.Update();
                    itemGuid = item2.UniqueId;
                }


                SPListItem item = list.Items[itemGuid];

                // Set up explicitely declared columns
                if (listItem.Columns.Count > 0)
                {
                    Dictionary<string, string> columnDictionary = listItem.Columns.ToDictionary(
                        col => col.FieldName,
                        col => ParserUtil.ReplaceAllLiveFields(col.Value, list.ParentWeb));

                    foreach (var col in columnDictionary)
                    {
                        ListUtil.EnsureListField(list, col.Key);
                        item[col.Key] = col.Value;
                    }

                    item.Update();
                }
            }

            switch (listItem.Type)
            {
                case "Folder":
                    {
                        //Thread.Sleep(300000);
                        OmListOperationVisitorHelper.ProcessFolder(listItem, list, web);
                        break;
                    }

                case "File":
                    {
                        OmListOperationVisitorHelper.ProcessFile(listItem, list, web);
                        break;
                    }

                case "Item":
                    {
                        OmListOperationVisitorHelper.ProcessItem(listItem, list, web);
                        break;
                    }

                default:
                    break;
            }
        }

        public void Visit(FixupView fixupView)
        {
            if (!string.IsNullOrEmpty(fixupView.Name))
            {
                SPView view = list.Views[fixupView.Name];
                if (view != null)
                {
                    foreach (InjectCTypeFields injectType in fixupView.InjectTypes)
                    {
                        injectType.Process(view, list);
                    }
                    foreach (InjectViewFields injectField in fixupView.InjectFields)
                    {
                        injectField.Process(view, list);
                    }
                }

            }
        }

        /// <summary>
        /// Processes Access Control List items in the web. 
        /// </summary>
        /// <param name="fixupACL">Object representing the FixupACL xml node</param>
        public void Visit(FixupACL fixupACL)
        {
            Logger.Info("Configuring list ACL: " + list.Title);

            if (!string.IsNullOrEmpty(fixupACL.RoleAssignments))
            {
                if (fixupACL.RoleAssignments.StartsWith("Break") && !list.HasUniqueRoleAssignments)
                {
                    Logger.Info("Breaking role inheritance: " + fixupACL.RoleAssignments);
                    list.BreakRoleInheritance(fixupACL.RoleAssignments == "BreakAndCopy");
                }
            }

            foreach (PrincipalListRole principalRole in fixupACL.Roles)
            {
                principalRole.Process(web, list);
            }

            web.Update();
        }

        public void Visit(AddFields addFields)
        {
            try
            {
                foreach (AddField field in addFields.Fields)
                {
                    Logger.Info("Adding field: " + field.Field);
                    list.Fields.AddFieldAsXml(field.Field, field.AddToDefaultView, SPAddFieldOptions.AddToAllContentTypes);
                    list.Update();
                }
            }
            catch (Exception e)
            {
                Logger.Info("Exception occured while adding fields");
                Logger.Error(e);
            }
        }

        public void Visit(AddCTypes addCTypes)
        {
            foreach (ContentTypeRef contentType in addCTypes.ContentTypes)
            {
                if (!string.IsNullOrEmpty(contentType.ID))
                    ListUtil.AddCType(list, contentType.ID);
                else
                    if (!string.IsNullOrEmpty(contentType.Name))
                        ListUtil.AddCTypeByName(list, contentType.Name);
            }

            list.Update();
        }
    }
}
